package com.halden.mycache.api;

import com.halden.mycache.support.EvictStrategy.EvictStrategy;
import com.halden.mycache.support.EvictStrategy.impl.LFUStrategy;
import com.halden.mycache.support.aop.AOFAspect;
import com.halden.mycache.support.saveStrategy.AOFSaveStrategy.IAOFSaveMode;
import com.halden.mycache.support.saveStrategy.AOFSaveStrategy.IAOFSaveStrategy;
import com.halden.mycache.support.saveStrategy.AOFSaveStrategy.impl.AOFSaveStrategy;
import com.halden.mycache.support.saveStrategy.AOFSaveStrategy.impl.AofKryoSerializeSaveMode;
import com.halden.mycache.support.saveStrategy.RDBSaveStrategy.IRDBSaveMode;
import com.halden.mycache.support.saveStrategy.RDBSaveStrategy.IRDBSaveStrategy;
import com.halden.mycache.support.saveStrategy.RDBSaveStrategy.impl.RdbKryoSerializeSaveModeRdb;
import com.halden.mycache.support.saveStrategy.RDBSaveStrategy.impl.RDBSaveStrategy;
import com.halden.mycache.core.IMyCache;
import com.halden.mycache.core.Impl.CacheValue;
import com.halden.mycache.exception.IllegalParameterException;
import com.halden.mycache.support.aop.SlowLogAspect;
import com.halden.mycache.support.listener.ICacheRemoveListener;
import com.halden.mycache.support.listener.ISlowLogListener;
import com.halden.mycache.support.listener.impl.LogCacheRemoveListener;
import com.sun.istack.internal.NotNull;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 内存工厂类，用于创建新的内存对象
 * @since 0.0.1
 */
public class CacheFactory<K,V> {

    /**
     * 持久化文件存储目录
     * @since 0.0.3
     */
    private static final String SAVE_PATH = System.getProperty("user.dir")+"/save/";

    /**
     * cache需要使用的集合类，默认使用HashMap
     * @since 0.0.1
     */
    private final Map<K,CacheValue<V>> map = new ConcurrentHashMap<>();

    /**
     * cache的大小， 默认为0
     * @since 0.0.1
     */
    private int size = 5;

    /**
     * cache使用的内存淘汰策略，默认为LFU
     * @since 0.0.1
     */
    private EvictStrategy evictStrategy = new LFUStrategy();

    /**
     * cache使用的持久化文件名，默认为rdb
     * @since 0.0.3
     */
    private String rdbSaveFileName = "rdb";

    /**
     * cache初始化时读取的持久化文件名，默认为rdb
     * @since 0.0.3
     */
    private String rdbReadFileName = "rdb";

    /**
     * cache使用的rdb持久化策略，默认为RDB存储
     * @since 0.0.3
     */
    private IRDBSaveStrategy rdbSaveStrategy = new RDBSaveStrategy();

    /**
     * rdbSaveStrategy使用的持久化模式，默认为kryo序列化存储
     * @since 0.0.3
     */
    private IRDBSaveMode rdbSaveMode = new RdbKryoSerializeSaveModeRdb();

    /**
     * 监听删除的监听器，默认使用logCacheRemoveListener
     * @since 0.0.4
     */
    private ICacheRemoveListener cacheRemoveListener = new LogCacheRemoveListener();

    /**
     * aof持久化文件的文件名，默认为aof
     */
    private String aofSaveFileName = "aof";

    /**
     * 实现aof的类，默认使用AOFSaveStrategy
     */
    private IAOFSaveStrategy aofSaveStrategy = new AOFSaveStrategy();

    /**
     * aof的持久化模式，默认为kryo
     */
    private IAOFSaveMode aofSaveMode = new AofKryoSerializeSaveMode();

    /**
     * aof最大记录数，默认为1000
     */
    private long aofMaxRecord = 1000;

    /**
     * 创建工厂实例
     * @since 0.0.1
     * @param <K>
     * @param <V>
     * @return 工厂实例
     */
    public static <K,V> CacheFactory<K,V> newInstance(){
        return new CacheFactory<K,V>();
    }

    /**
     * 设置cache的大小
     * @param size, 必须大于5，为了便于内存淘汰
     * @return 工厂实例
     * @since 0.0.1
     */
    public CacheFactory<K,V> size(int size){
        if (size < 5){
            throw new IllegalParameterException("非法的参数");
        }
        this.size = size;
        return this;
    }

    /**
     * 设置cache的内存淘汰策略
     * @param evictStrategy
     * @return 工厂实例
     * @since 0.0.1
     */
    public CacheFactory<K,V> evictStrategy(@NotNull EvictStrategy evictStrategy){
        this.evictStrategy = evictStrategy;
        return this;
    }

    /**
     * 设置持久化策略
     * @param saveStrategy
     * @return 工厂实例
     * @since 0.0.3
     */
    public CacheFactory<K,V> saveStrategy(@NotNull IRDBSaveStrategy saveStrategy){
        this.rdbSaveStrategy = saveStrategy;
        return this;
    }

    /**
     * 设置持久化模式
     * @param saveMode
     * @return 工厂实例
     * @since 0.0.3
     */
    public CacheFactory<K,V> saveMode(@NotNull IRDBSaveMode saveMode){
        this.rdbSaveMode = saveMode;
        return this;
    }

    /**
     * 设置持久化文件
     * @param fileName
     * @return 工厂实例
     * @since 0.0.3
     */
    public CacheFactory<K,V> rdbSaveFile(@NotNull String fileName){
        this.rdbReadFileName = fileName;
        return this;
    }

    /**
     * 设置读取持久化文件的文件名
     * @param fileName
     * @return 工厂实例
     * @since 0.0.3
     */
    public CacheFactory<K,V> rdbReadFile(@NotNull String fileName){
        this.rdbReadFileName = fileName;
        return this;
    }

    /**
     * 设置删除监听器
     * @param cacheRemoveListener
     * @return
     * @since 0.0.4
     */
    public CacheFactory<K,V> cacheRemoveListener(@NotNull ICacheRemoveListener cacheRemoveListener){
        this.cacheRemoveListener = cacheRemoveListener;
        return this;
    }

    /**
     * 设置开启慢日志
     * @return
     * @since 0.0.4
     */
    public CacheFactory<K,V> openSlowLog(){
        SlowLogAspect.openSlowLog();
        return this;
    }

    /**
     * 添加慢日志监听器
     * @param slowLogListener
     * @return
     * @since 0.0.4
     */
    public CacheFactory<K,V> addSlowListener(@NotNull ISlowLogListener slowLogListener){
        SlowLogAspect.addSlowLogListener(slowLogListener);
        return this;
    }

    /**
     * 设置aof持久化文件名
     * @param fileName
     * @return
     * @since 0.0.5
     */
    public CacheFactory<K,V> aofSaveFile(@NotNull String fileName){
        this.aofSaveFileName = fileName;
        return this;
    }

    /**
     * 设置aof持久化类
     * @param aofSaveStrategy
     * @return
     * @since 0.0.5
     */
    public CacheFactory<K,V> aofStrategy(IAOFSaveStrategy aofSaveStrategy){
        this.aofSaveStrategy = aofSaveStrategy;
        return this;
    }

    /**
     * 设置aof持久化模式
     * @param aofSaveMode
     * @return
     * @since 0.0.5
     */
    public CacheFactory<K,V> aofSaveMode(IAOFSaveMode aofSaveMode){
        this.aofSaveMode = aofSaveMode;
        return this;
    }

    /**
     * 设置aof最大记录数
     * @param aofMaxRecord
     * @return
     * @since 0.0.5
     */
    public CacheFactory<K,V> aofMaxRecord(long aofMaxRecord){
        this.aofMaxRecord = aofMaxRecord;
        return this;
    }

    /**
     * 构建cache实例
     * @return cache实例
     * @since 0.0.1
     */
    public IMyCache<K,V> build(){
        ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
        IMyCache myCache = context.getBean("myCache", IMyCache.class);
        myCache.setMap(this.map);
        myCache.setSize(this.size);
        myCache.setLength(0);
        myCache.setEvictStrategy(this.evictStrategy);
        this.rdbSaveStrategy.setSaveMode(this.rdbSaveMode);
        myCache.setSaveStrategy(this.rdbSaveStrategy, SAVE_PATH+rdbSaveFileName);
        myCache.readRdbFile(SAVE_PATH+rdbReadFileName);
        myCache.setCacheRemoveListener(this.cacheRemoveListener);
        AOFAspect.setFileName(SAVE_PATH+aofSaveFileName);
        this.aofSaveStrategy.setSaveMode(this.aofSaveMode);
        this.aofSaveStrategy.setMaxRecord(this.aofMaxRecord);
        AOFAspect.setAofSaveStrategy(this.aofSaveStrategy);
        myCache.setAofSaveStrategy(this.aofSaveStrategy);
        return myCache;
    }

}
